perm filename TESTIN.LSP[F87,JMC] blob
sn#850849 filedate 1987-12-27 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00003 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 -*- Syntax: Common-lisp Package: PZ Default-character-style: (:FIX :BOLD :NORMAL) -*-
C00007 00003 SHOWBOARD is the main display function. It prints out almost all of the board state of
C00012 ENDMK
C⊗;
;;; -*- Syntax: Common-lisp; Package: PZ; Default-character-style: (:FIX :BOLD :NORMAL) -*-
;;; There are several boards included here which are useful for testing and debugging.
(defparameter *easy-puzzle*
(let ((*default-initial-position*
'(1 2 3 4 5 6 7 8 9 10 11 12 13 14 :blank 15)))
(make-board :blank 15 :name "Easy-Board")))
(defparameter *easy-puzzle2*
(let ((*default-initial-position*
'(1 2 3 4 5 6 7 8 9 10 :blank 12 13 14 11 15)))
(make-board :blank 11 :name "Easy Puzzle 2")))
;;; *STUCK* is an unsolvable board. (It is not reachable from the solved postion.)
(defparameter *stuck* (let ((*default-initial-position*
'(1 2 3 4 5 6 7 8 9 10 11 12 13 15 14 :BLANK)))
(make-board :blank 16 :name "Stuck Board")))
(defparameter *blocked-4* (let ((*default-initial-position*
'(1 2 3 6 7 9 11 4 5 12 8 :BLANK 14 15 10 13)))
(make-board :blank 12 :name "Blocked 4")))
(defparameter *blocked-at-13* (let ((*default-initial-position*
'(1 2 3 4 5 6 7 8 9 10 11 15 :BLANK 12 14 13)))
(make-board :blank 13 :name "Blocked 4")) )
(defparameter *solved-board* (make-board :name "Solved Board"))
(evaluate-initial-position *solved-board*)
(defparameter *random-board* (make-board :name "Random Board"))
;;; CHECK-GOODNESS is just an error checking routine to make sure that we don't attempt to
;;; solve a malformed board. One test that it is missing is the parity test to make sure
;;; that the board it is given is actually solvable - I wasn't sure how it went. The
;;; RANDOM-BOARD function only generates solvable boards, though.
(defun check-goodness (board)
(unless (or (unless (numberp (board-size board))
(Format t "Non numeric board size: ~s in ~a"
(board-size board) (board-name board)) t)
(when (or (not (numberp (board-blank board)))
(> (board-blank board) (expt (board-size board) 2))
(> 1 (board-blank board)))
(format t "~&The Blank is said to be in position ~s in ~s~&"
(board-blank board) (board-name board)) t)
(unless (eq (position-contents (board-blank board) board) :blank)
(format t "~&The :BLANK is not in square ~d in ~a.~&"
(board-blank board) (board-name board)) t)
(unless (every #'(lambda (tile)
(find tile (board-position board) :key #'identity))
*default-initial-position*)
(format t "~&In ~a, some tile was not found in the board position ~a, with contents~&~a~&"
(board-name board) (board-position board)
(coerce (board-position board) 'list)) t))
t))
;;; SHOWBOARD is the main display function. It prints out almost all of the board state of
;;; any interest. It doesn't print out the movelist, because it's too lengthly. The
;;; (VALUES) call at the end just keeps the thing from printing an extra NIL when called at
;;; the Command: level.
(defun showboard (board)
(check-goodness board)
(format t "~& ~'b⊂~a~⊃~&~{ ~s~10t~s~20t~s~30t~s~&~}~& ~
~'i⊂Blank: ~s~15tCompleted Chain: ~s~39tLast-complete-row: ~s~
~65tBlank-Origin: ~s Moves: ~s~⊃~&"
(board-name board)
(Coerce (board-position board) 'list)
(board-blank board)(board-completed-chain board)
(board-last-complete-row board)(board-blank-origin board)
(length (board-moves board)))
(format t "~& ~'i⊂Acceptances: ~s Rejections: ~s Nodes Considered: ~s ~
Ply Depth: ~s Queue Length: ~s~⊃~&"
*acceptances* *rejections* *nodes-considered* (ply-depth board)
(length (fifo-queue-line *queue*)))
(showstats)
(values))
;;; SHOWSTATS shows the statistics on how many times each of the heuristics has succeeded.
(defun showstats ()
(format t "~& Better Heuristics: ~{~25t~:(~a:~) ~a~↑~55t~:(~a: ~a~&~)~}~&"
(loop for heu in *better-measures*
collect heu
collect (get heu :success)))
(format t "~& Worse Heuristics: ~{~25t~:(~a:~) ~a~↑~55t~:(~a: ~a~&~)~}~&"
(loop for heu in *worse-measures*
collect heu
collect (get heu :success)))
(values))
;;; Generate a random board position which is still solvable. Do this by moving the blank
;;; at random 300 times. Each time through the loop, get the legal moves from the
;;; Stored-Succesors function and choose one at random.
(defun random-board (&key (board *random-board*)(pathlen 300))
(copy-board-position board *solved-board*)
(initialize-problem board)
(loop for count from 1 to pathlen
for moves = (stored-successors (list (board-blank board)) board)
do (move (nth (random (length moves)) moves) board))
board)
;;; PLY-DEPTH is only used by the SHOWBOARD function to show the intermediate state of the
;;; calculation. It shows how many more moves the next node on the queue has than the
;;; *base-board* has.
(defun ply-depth (&optional (bb *base-board*))
(- (length (first (fifo-queue-line *queue*)))
(length (board-moves bb))))
;;; CLEAR-HEURISTIC-STATISTICS is invoked at initialization of the problem to set the
;;; accumulated successes of all the heuristics back to zero. These statistics are
;;; accumulated on each heuristic's property list. They are incremented by MAY-ACCEPT and
;;; MAY-REJECT.
(defun clear-heuristic-statistics ()
(mapc #'(lambda (heu)
(setf (get heu :success) 0))
*worse-measures*)
(mapc #'(lambda (heu)
(setf (get heu :success) 0))
*better-measures*))